#include "utils/network.h"

#if defined(_WIN32)
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#elif defined(__unix__) || defined(__APPLE__)
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif

namespace netutil {
	std::string CURRENT_IP4 = "";
	namespace {
		std::string detect_ip() {
#if defined(_WIN32)
			WSADATA wsaData;
			WSAStartup(MAKEWORD(2, 2), &wsaData);
			char ac[80];
			if (gethostname(ac, sizeof(ac)) == SOCKET_ERROR) return "";
			struct hostent *phe = gethostbyname(ac);
			if (!phe) return "";
			for (int i = 0; phe->h_addr_list[i] != 0; ++i) {
				struct in_addr addr;
				memcpy(&addr, phe->h_addr_list[i], sizeof(struct in_addr));
				std::string ip = inet_ntoa(addr);
				if (ip != "127.0.0.1") return ip;
			}
			return "";
#elif defined(__unix__) || defined(__APPLE__)
			struct ifaddrs *ifap, *ifa;
			void           *tmpAddrPtr = nullptr;
			std::string     result;
			getifaddrs(&ifap);
			for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
				if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
					tmpAddrPtr = &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
					char addressBuffer[INET_ADDRSTRLEN];
					inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
					std::string ip(addressBuffer);
					if (ip != "127.0.0.1") result = ip;
				}
			}
			freeifaddrs(ifap);
			return result;
#else
			return "";
#endif
		}
	} // namespace

	void initNetWork() {
		if (CURRENT_IP4.empty()) {
			CURRENT_IP4 = detect_ip();
		}
	}

} // namespace netutil
